package info.thereisonlywe.onenesspathfinder.ui;

import info.thereisonlywe.core.project.ProjectConstants;
import info.thereisonlywe.core.project.ProjectLocalization;
import info.thereisonlywe.core.toolkit.GUIToolkit;
import info.thereisonlywe.core.toolkit.PrimitiveToolkit;
import info.thereisonlywe.core.toolkit.StringToolkit;
import info.thereisonlywe.core.toolkit.TableScrollingToolkit;
import info.thereisonlywe.core.toolkit.ThreadToolkit;
import info.thereisonlywe.quran.text.QuranicText;
import info.thereisonlywe.quran.text.QuranicTextIdentifier;
import info.thereisonlywe.quran.text.QuranicTextList;
import info.thereisonlywe.quran.text.QuranicTextManager;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import com.jidesoft.swing.SearchableUtils;
import com.jidesoft.swing.TableSearchable;

public class TextConfigurationDialog {

	private static JDialog dialog;
	private static JTable table_Texts;
	private static JScrollPane scrollPane_Texts;
	private static JPanel panel;
	private static JCheckBox checkBox_Show;
	private static JCheckBox checkBox_Preferred;
	private static JButton button_MoveTextUp;
	private static JButton button_MoveTextDown;
	private static ArrayList<Integer> indices = new ArrayList<>();
	private static QuranicTextIdentifier texts[];
	private static JLabel label;

	/**
	 * @wbp.parser.entryPoint
	 */
	private static void init()
	{
		if (dialog != null) return;
		dialog = new JDialog();
		dialog.setIconImage(null);
		dialog.setTitle(ProjectLocalization.getString(
				ProjectConstants.ONENESS_PATHFINDER_PROJECT, "TextManagement"));
		dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		dialog.setResizable(false);
		dialog.setPreferredSize(new Dimension(600, 375));
		dialog.setSize(new Dimension(600, 375));
		dialog.setModal(true);
		dialog.getContentPane().setLayout(new BorderLayout());
		dialog.addWindowListener(new WindowAdapter()
		{

			@Override
			public void windowClosing(WindowEvent e)
			{
				dialog.setVisible(false);
				UIDelegate.setOpenDialog(false);
			}
		});

		scrollPane_Texts = new JScrollPane();

		panel = new JPanel();
		panel.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 3));

		checkBox_Show = new JCheckBox(ProjectLocalization.getString(
				ProjectConstants.ONENESS_PATHFINDER_PROJECT, "Shown"));
		panel.add(checkBox_Show);

		checkBox_Preferred = new JCheckBox(ProjectLocalization.getString(
				ProjectConstants.ONENESS_PATHFINDER_PROJECT, "Preferred"));
		panel.add(checkBox_Preferred);

		button_MoveTextUp = new JButton();
		button_MoveTextUp.setPreferredSize(new Dimension(24, 24));
		panel.add(button_MoveTextUp);

		button_MoveTextDown = new JButton();
		button_MoveTextDown.setPreferredSize(new Dimension(24, 24));
		panel.add(button_MoveTextDown);

		table_Texts = new JTable();

		table_Texts.setModel(new javax.swing.table.DefaultTableModel(
				new Object[][] {

				}, new String[] {

				}));

		table_Texts.setFillsViewportHeight(true);
		table_Texts
				.setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

		DefaultTableModel tableModel = new DefaultTableModel(
				getSortedTextOrder(), getTableColumnNames())
		{
			private static final long serialVersionUID = 1L;

			@Override
			public Class<String> getColumnClass(int columnIndex)
			{
				return String.class;
			}

			@Override
			public boolean isCellEditable(int rowIndex, int columnIndex)
			{
				return false;
			}
		};

		table_Texts.setColumnSelectionAllowed(false);
		table_Texts.setModel(tableModel);
		table_Texts.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
		TableColumnModel cmodel = table_Texts.getColumnModel();
		cmodel.getColumn(0).setPreferredWidth(100);
		cmodel.getColumn(1).setPreferredWidth(275);
		cmodel.getColumn(2).setPreferredWidth(120);
		cmodel.getColumn(3).setPreferredWidth(45);
		cmodel.getColumn(4).setPreferredWidth(50);
		table_Texts.setSelectionBackground(new Color(255, 200, 250));
		table_Texts.getTableHeader().setDefaultRenderer(
				new HeaderRenderer(table_Texts));
		DefaultTableCellRenderer rend = new DefaultTableCellRenderer()
		{

			private static final long serialVersionUID = 1L;

			@Override
			public Component getTableCellRendererComponent(JTable table,
					Object value, boolean isSelected, boolean hasFocus,
					int row, int column)
			{

				super.getTableCellRendererComponent(table, value, isSelected,
						hasFocus, row, column);

				QuranicText qt = QuranicTextList.getTextByID(texts[indices
						.get(row)].getID());

				if (qt == null)
				{
					setForeground(new Color(85, 15, 0));
				}

				else if (qt.isPreferred())
				{
					setForeground(new Color(5, 29, 107));
				}

				else if (qt.showInBrowser())
				{
					setForeground(Color.black);
				}

				else
				{
					setForeground(Color.DARK_GRAY);
				}

				return this;
			}

		};
		rend.setOpaque(true);
		rend.setHorizontalAlignment(JLabel.CENTER);
		cmodel.getColumn(0).setCellRenderer(rend);
		cmodel.getColumn(1).setCellRenderer(rend);
		cmodel.getColumn(2).setCellRenderer(rend);
		cmodel.getColumn(3).setCellRenderer(rend);
		cmodel.getColumn(4).setCellRenderer(rend);

		TableSearchable ts = SearchableUtils.installSearchable(table_Texts);
		ts.setSearchColumnIndices(new int[] { 0, 1, 2, 3, 4 });

		scrollPane_Texts.setViewportView(table_Texts);

		button_MoveTextDown
				.setIcon(new ImageIcon(TextConfigurationDialog.class
						.getResource(UIConstants.RESOURCES_ICONS_PATH
								+ "movedown.png")));
		button_MoveTextUp.setIcon(new ImageIcon(TextConfigurationDialog.class
				.getResource(UIConstants.RESOURCES_ICONS_PATH + "moveup.png")));

		button_MoveTextUp.setFocusPainted(false);
		button_MoveTextUp.setMargin(new Insets(0, 0, 0, 0));
		button_MoveTextUp.setContentAreaFilled(false);
		button_MoveTextUp.setBorderPainted(false);
		button_MoveTextUp.setOpaque(false);

		button_MoveTextDown.setFocusPainted(false);
		button_MoveTextDown.setMargin(new Insets(0, 0, 0, 0));
		button_MoveTextDown.setContentAreaFilled(false);
		button_MoveTextDown.setBorderPainted(false);
		button_MoveTextDown.setOpaque(false);

		dialog.getContentPane().setLayout(new BorderLayout());
		dialog.getContentPane().add(panel, BorderLayout.SOUTH);

		label = new JLabel("");
		panel.add(label);
		dialog.getContentPane().add(scrollPane_Texts, BorderLayout.CENTER);

		KeyboardFocusManager.getCurrentKeyboardFocusManager()
				.addKeyEventDispatcher(new KeyEventDispatcher()
				{
					@Override
					public boolean dispatchKeyEvent(KeyEvent e)
					{
						boolean keyHandled = false;
						if (e.getID() == KeyEvent.KEY_PRESSED
								&& dialog.isVisible())
						{
							if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
							{
								dialog.setVisible(false);
								UIDelegate.setOpenDialog(false);
								keyHandled = true;
							}
						}
						return keyHandled;
					}
				});

		initListeners();

	}

	private static void initListeners()
	{

		TextSelectionListener listener = new TextSelectionListener();
		table_Texts.getSelectionModel().addListSelectionListener(listener);
		table_Texts.getColumnModel().getSelectionModel()
				.addListSelectionListener(listener);

		button_MoveTextDown.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				if (table_Texts.getSelectedRowCount() < 1) return;
				int indices[] = getTextIndices(table_Texts.getSelectedRows());
				Arrays.sort(indices);
				boolean success = false;
				for (int i = indices.length - 1; i >= 0; i--)
				{
					if (indices[i] > -1)
					{
						int index = QuranicTextList.indexOf(texts[indices[i]]);
						if (index > -1)
							success = QuranicTextList.moveTextDown(index) ? true
									: success;
					}
				}
				if (success) refreshTextsOrder();
				UIDelegate.VersePaneHook.refresh();
			}
		});

		button_MoveTextUp.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				if (table_Texts.getSelectedRowCount() < 1) return;
				int indices[] = getTextIndices(table_Texts.getSelectedRows());
				Arrays.sort(indices);
				boolean success = false;
				for (int i = 0; i < indices.length; i++)
				{
					if (indices[i] > -1)
					{
						int index = QuranicTextList.indexOf(texts[indices[i]]);
						if (index > -1)
							success = QuranicTextList.moveTextUp(index) ? true
									: success;
					}
				}
				if (success) refreshTextsOrder();
				UIDelegate.VersePaneHook.refresh();
			}

		});

		checkBox_Show.addActionListener(new ActionListener()
		{

			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				int indices[] = getTextIndices(table_Texts.getSelectedRows());
				if (indices != null && indices.length > 0)
					showClicked(indices);
			}

		});

		checkBox_Preferred.addActionListener(new ActionListener()
		{

			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				int indices[] = getTextIndices(table_Texts.getSelectedRows());
				if (indices != null && indices.length > 0)
					preferredClicked(indices);
			}

		});
	}

	private static int[] getTextIndices(int[] selectedRows)
	{
		int[] result = new int[selectedRows.length];
		for (int i = 0; i < result.length; i++)
		{
			result[i] = indices.get(selectedRows[i]);
		}
		return result;
	}

	private static String[][] getSortedTextOrder()
	{
		texts = QuranicTextManager.getTextsOnServer();

		String[][] tableData = new String[texts.length][5];

		indices.clear();

		for (int i = 0; i < QuranicTextList.getTextCount(); i++)
		{
			QuranicText qt = QuranicTextList.getText(i);
			if (qt.getOrder() == indices.size())
			{
				for (int j = 0; j < texts.length; j++)
				{
					if (qt.getIdentifier().getID() == texts[j].getID())
					{
						indices.add(Integer.valueOf(j));
						i = -1;
					}
				}

			}
			if (indices.size() == QuranicTextList.getNumberOfShownTexts())
				break;
		}

		int counter = 0;

		String[] leftEntries = new String[texts.length - indices.size()];

		for (int i = 0; i < texts.length; i++)
		{
			if (indices.contains(i)) continue;
			int index = QuranicTextList.indexOf(texts[i].getID());
			if (index != -1)
			{
				QuranicText qt = QuranicTextList.getText(index);
				leftEntries[counter] = new String(qt.getIdentifier()
						.getLanguageCode()
						+ "-"
						+ qt.getIdentifier().getAuthor()
						+ "-"
						+ qt.getIdentifier().getType() + "-" + i);
				counter++;
			}
			else
			{
				leftEntries[counter] = new String(texts[i].getLanguageCode()
						+ "-" + texts[i].getAuthor() + "-" + texts[i].getType()
						+ "-" + i);
				counter++;
			}

		}

		Arrays.sort(leftEntries, String.CASE_INSENSITIVE_ORDER);

		counter = 0;

		for (int i = indices.size(); i < texts.length; i++)
		{
			int index = Integer.parseInt(new String(leftEntries[counter]
					.substring(leftEntries[counter].lastIndexOf("-") + 1)));
			indices.add(Integer.valueOf(index));
			counter++;
		}

		for (int i = 0; i < tableData.length; i++)
		{

			tableData[i][0] = texts[indices.get(i)].getLanguage();
			tableData[i][1] = texts[indices.get(i)].getAuthor();
			tableData[i][2] = texts[indices.get(i)].getTypeAsString();

			int ID = texts[indices.get(i)].getID();
			QuranicText text = QuranicTextList.getTextByID(ID);
			if (text != null)
			{
				tableData[i][3] = text.getCompletion() + "%";
				tableData[i][4] = new String(
						String.valueOf((text.getOrder()) + 1));
			}
			else
			{
				tableData[i][3] = "?";
				tableData[i][4] = "0";
			}
		}

		return tableData;
	}

	private static void refreshTextsOrder()
	{

		if (dialog.isVisible())
		{
			SwingUtilities.invokeLater(new Runnable()
			{
				@Override
				public void run()
				{
					setTextsOrder();
				}
			});
		}

		else
		{
			setTextsOrder();
		}
	}

	private static void setTextsOrder()
	{
		int[] selectedIndices = table_Texts.getSelectedRows();

		for (int i = 0; i < selectedIndices.length; i++) // translates table
															// indices to
															// textlist indices
		{
			selectedIndices[i] = indices.get(selectedIndices[i]);
		}

		String[][] ordered = getSortedTextOrder();

		TableModel tm = table_Texts.getModel();

		for (int i = 0; i < tm.getRowCount(); i++)
		{
			for (int j = 0; j < tm.getColumnCount(); j++)
			{
				table_Texts.getModel().setValueAt(ordered[i][j], i, j);
			}
		}

		table_Texts.clearSelection();

		int[] selectedRows = new int[selectedIndices.length];

		for (int i = 0; i < selectedIndices.length; i++)
		{
			for (int j = 0; j < indices.size(); j++)
			{
				if (indices.get(j).equals(Integer.valueOf(selectedIndices[i])))
				{
					table_Texts.addRowSelectionInterval(j, j);
					selectedRows[i] = j;
				}
			}
		}

		table_Texts.repaint();
		table_Texts.revalidate();

		if (selectedRows != null && selectedRows.length > 0)
		{
			int a = PrimitiveToolkit.getClosestToRadix(selectedRows, 0);
			int b = PrimitiveToolkit.getClosestToRadix(selectedRows,
					indices.size());
			if (a > b)
			{
				int tmp = a;
				a = b;
				b = tmp;
			}
			TableScrollingToolkit.centerCells(table_Texts, a, b, 0, 4);
		}

		selectedIndices = null;
		selectedRows = null;
		ordered = null;
		tm = null;
	}

	private static String[] getTableColumnNames()
	{
		return new String[] {
				ProjectLocalization.getString(
						ProjectConstants.ONENESS_PATHFINDER_PROJECT,
						"textsTable.language"),
				ProjectLocalization.getString(
						ProjectConstants.ONENESS_PATHFINDER_PROJECT,
						"textsTable.author"),
				ProjectLocalization.getString(
						ProjectConstants.ONENESS_PATHFINDER_PROJECT,
						"textsTable.type"),
				"%",
				ProjectLocalization.getString(
						ProjectConstants.ONENESS_PATHFINDER_PROJECT,
						"textsTable.order") };
	}

	private static void setControls(final boolean flag)
	{
		SwingUtilities.invokeLater(new Runnable()
		{

			@Override
			public void run()
			{
				button_MoveTextDown.setEnabled(flag);
				button_MoveTextUp.setEnabled(flag);
				checkBox_Preferred.setEnabled(flag);
				checkBox_Show.setEnabled(flag);
				if (!flag) label.setText(ProjectLocalization.getString(
						ProjectConstants.CORE_PROJECT, "DownloadingFromServer"));
				else label.setText("");

			}
		});
	}

	private static boolean download(final int indices[])
	{
		boolean error = false;
		setControls(false);
		if (indices == null || indices.length < 1)
		{
			setControls(true);
			return !error;
		}
		for (int i = 0; i < indices.length; i++)
		{
			int id = texts[indices[i]].getID();
			boolean b = QuranicTextManager.updateText(id);
			if (!b)
			{
				error = true;
				break;
			}
			else
			{
				QuranicTextList.addText(id);
				if (checkBox_Preferred.isSelected()) break;
			}

		}

		setControls(true);

		return !error;
	}

	private static void preferredClicked(final int[] indices)
	{
		Runnable refresh = new Thread()
		{
			@Override
			public void run()
			{
				final boolean selected = checkBox_Preferred.isSelected();
				int index = QuranicTextList.indexOf(texts[indices[0]].getID());
				if (index == -1)
				{
					if (!download(indices))
					{
						checkBox_Preferred.setSelected(false);
						UIDelegate.setOpenDialog(true);
						GUIToolkit.showErrorDialog(ProjectLocalization
								.getString(ProjectConstants.CORE_PROJECT,
										"DownloadError"), StringToolkit
								.multiLine(ProjectLocalization.getString(
										ProjectConstants.CORE_PROJECT,
										"DownloadError.Body"),
										UIConstants.MAX_CHARS_PER_LINE));
						UIDelegate.setOpenDialog(false);
						return;
					}
					else
					{
						index = QuranicTextList.indexOf(texts[indices[0]]
								.getID());
					}
				}
				QuranicTextList.setPreferred(index, selected);
				// setOrientation();
				table_Texts.repaint();
				if (selected)
				{
					while (!QuranicTextList.getText(index).isLoaded())
					{
						ThreadToolkit.sleep(50);
					}
				}
				if (MainFrame.view_Windows.isSearchContainerMounted())
					MainFrame.view_Windows.getSearchPanel().refreshResults();
				new UIDelegate.SectionPaneHook.RefreshTask(UIDelegate
						.getDisplayedVerse().getVerseNumber() - 1).execute();
			}
		};
		new Thread(refresh).start();
	}

	private static void showClicked(final int[] indices)
	{
		if (table_Texts.getSelectedRowCount() < 1) return;
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{
				boolean processed = false;
				boolean error = false;
				for (int i = 0; i < indices.length; i++)
				{
					int index = QuranicTextList.indexOf(texts[indices[i]]);
					if (index > -1)
					{
						QuranicTextList.setShownInBrowser(index,
								checkBox_Show.isSelected());
						processed = true;
					}
					else if (download(indices))
					{
						index = QuranicTextList.indexOf(texts[indices[i]]);
						QuranicTextList.setShownInBrowser(index,
								checkBox_Show.isSelected());
						processed = true;
					}
					else
					{
						for (int j = i; j < indices.length; j++)
						{
							index = QuranicTextList.indexOf(texts[indices[j]]);
							if (index > -1)
							{
								QuranicTextList.setShownInBrowser(index,
										checkBox_Show.isSelected());
								processed = true;
							}
						}
						error = true;
						break;
					}
				}
				if (processed)
				{
					ThreadToolkit.sleep(150 + (10 * indices.length));
					refreshTextsOrder();
					UIDelegate.VersePaneHook.refresh();
				}
				if (error)
				{
					checkBox_Show.setSelected(false);
					UIDelegate.setOpenDialog(true);
					GUIToolkit.showErrorDialog(ProjectLocalization.getString(
							ProjectConstants.CORE_PROJECT, "DownloadError"),
							StringToolkit.multiLine(ProjectLocalization
									.getString(ProjectConstants.CORE_PROJECT,
											"DownloadError.Body"),
									UIConstants.MAX_CHARS_PER_LINE));
					UIDelegate.setOpenDialog(false);
				}
			}
		};
		new Thread(r).start();
	}

	// private void setOrientation() {
	//
	// int pref = QuranicTextList.getPreferred();
	// ComponentOrientation co;
	// if (pref < 0 || QuranicTextList.getText(pref).isRTL())
	// co = ComponentOrientation.RIGHT_TO_LEFT;
	// else
	// co = ComponentOrientation.LEFT_TO_RIGHT;
	// scrollPane_Texts.applyComponentOrientation(co);
	// }

	private static class HeaderRenderer implements TableCellRenderer {

		DefaultTableCellRenderer renderer;

		public HeaderRenderer(JTable table)
		{
			renderer = (DefaultTableCellRenderer) table.getTableHeader()
					.getDefaultRenderer();
			renderer.setHorizontalAlignment(JLabel.CENTER);
		}

		@Override
		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int col)
		{
			return renderer.getTableCellRendererComponent(table, value,
					isSelected, hasFocus, row, col);
		}
	}

	public synchronized static void showDialog()
	{
		init();
		dialog.setLocation(GUIToolkit.getCenteredWindowPosition(
				dialog.getWidth(), dialog.getHeight()));
		UIDelegate.setOpenDialog(true);
		dialog.setVisible(true);
	}

	private static class TextSelectionListener implements ListSelectionListener {
		@Override
		public void valueChanged(ListSelectionEvent e)
		{

			if (e.getValueIsAdjusting()) { return; }

			int indices[] = getTextIndices(table_Texts.getSelectedRows());

			for (int i = 0; i < indices.length; i++)
			{
				if (indices[i] <= -1) continue;
				QuranicText text = QuranicTextList
						.getTextByID(texts[indices[i]].getID());
				if (text != null)
				{
					checkBox_Show.setSelected(text.showInBrowser());
					checkBox_Preferred.setSelected(text.isPreferred());
				}
				else
				{
					checkBox_Show.setSelected(false);
					checkBox_Preferred.setSelected(false);
				}
			}
		}
	}

}
